#region Copyright
/// <copyright>
/// Copyright (c) 2007 Ilia Shramko.
/// Released under the terms of the GNU General Public License.
/// </copyright>
#endregion

using System;
using System.Collections.Generic;
using System.Text;

namespace Osh.ProgDvb
{
	public struct DeviceId : IComparable
	{
		public static readonly DeviceId Invalid;
		public const int Size = 4+1+8;
		public const int StringSize = Size*2 + 2;

		private uint _subId;
		private byte _type;
		private ulong _dllId;

		/// <summary>
		/// 
		/// </summary>
		/// <param name="deviceId">XXXXXXXX-XX-XXXXXXXXXXXXXXXX</param>
		public DeviceId(string deviceId)
		{
			if(deviceId == null)
				throw new ArgumentNullException("deviceId");
			if(deviceId.Length != StringSize)
				throw new ArgumentOutOfRangeException("deviceId");
			
			_subId = HexConverter.ToUInt32(deviceId, 0);
			_type = HexConverter.ToByte(deviceId, 9);
			_dllId = HexConverter.ToUInt64(deviceId, 12);
		}

		public DeviceId(byte[] data) : this(data, 0)
		{
		}

		public DeviceId(byte[] data, int offset)
		{
			_subId = BitConverter.ToUInt32(data, offset); offset += 4;
			_type = data[offset++];
			_dllId = BitConverter.ToUInt64(data, offset);
		}

		public uint SubId
		{
			get { return _subId; }
			set { _subId = value; }
		}

		public TunerType Type
		{
			get { return (TunerType)_type; }
			set { _type = (byte)value; }
		}

		public ulong DllId
		{
			get { return _dllId; }
			set { _dllId = value; }
		}

		public override string ToString()
		{
			char[] chars = new char[StringSize];
			int position = 0;
			HexConverter.ToHex(_subId, chars, position); position += 8;
			chars[position++] = '-';
			HexConverter.ToHex(_type, chars, position);  position += 2;
			chars[position++] = '-';
			HexConverter.ToHex(_dllId, chars, position);
			return new string(chars);
		}

		public static bool TryParse(string str, out DeviceId deviceId)
		{
			deviceId = DeviceId.Invalid;
			try
			{
				deviceId = new DeviceId(str);
				return true;
			}
			catch(Exception)
			{
				return false;
			}
		}

		#region IComparable Members
		public int CompareTo(object obj)
		{
			DeviceId otherId = (DeviceId)obj;
			if(this._subId > otherId._subId) return 1;
			if(this._subId < otherId._subId) return -1;
			if(this._type > otherId._type) return 1;
			if(this._type < otherId._type) return -1;
			if(this._dllId > otherId._dllId) return 1;
			if(this._dllId < otherId._dllId) return -1;
			return 0;
		}
		#endregion

		public override int GetHashCode()
		{
			return (int)(_subId ^ _type ^ ((uint)_dllId) ^ (int)(_dllId >> 32));
		}

		public override bool Equals(object obj)
		{
			if(obj == null)
				return false;

			if(!(obj is DeviceId))
				return false;

			return this.CompareTo(obj) == 0;
		}

		public bool Equals(DeviceId deviceId)
		{
			if((object)deviceId == null)
				return false;

			return this.CompareTo(deviceId) == 0;
		}

		public static bool operator ==(DeviceId a, DeviceId b)
		{
			if(object.ReferenceEquals(a, b))
				return true;

			if(((object)a == null) || ((object)b == null))
				return false;

			return a.Equals(b);
		}

		public static bool operator !=(DeviceId a, DeviceId b)
		{
			return !(a == b);
		}
	}
}
